#ifndef __MSG_Q_HPP__

#define __MSG_Q_HPP__
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <cstring>
#include "ChainOfResponsibility.hpp"

using std::cout;
using std::endl;
using std::string;

const int CreatMsg_Mode = IPC_CREAT | IPC_EXCL | 0666;
const int GetMsg_Mode = IPC_CREAT;
const string defaultfilename = "/usr/bin";
const int defaultproj_od = 0x112;

enum
{
    Creat_Key_Error,
    Msgget_Error,
    Msgctrl_Error,
    Msgsnd_Error,
    MsgsndType_Error,
    MsgRcv_Error,
    MsgRcvType_Error
};

struct Msgbuf
{
    long mtype;
    char mtext[1024];
};

// 对消息队列接口进行封装
class Msg_q
{
    // 获取key值
    int GetKey(const string &pathname, const int &proj_id)
    {
        key_t k = ftok(pathname.c_str(), proj_id);
        if (k < 0)
        {
            cout << " ftok error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(Creat_Key_Error);
        }
        return k;
    }

public:
    Msg_q(const string &pathname, const int &proj_id, const int &mode)
    {
        key_ = GetKey(pathname, proj_id);
        // 依照mode的方式打开文件
        msgid_ = msgget(key_, mode);
        if (msgid_ < 0)
        {
            cout << " msgget error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(Msgget_Error);
        }
    }

    // 发送消息
    void Send_Base(const string &message_, int mtype_)
    {
        struct Msgbuf bufferin;
        memset(bufferin.mtext, 0, sizeof(bufferin.mtext));
        bufferin.mtype = mtype_;
        memcpy(bufferin.mtext, message_.c_str(), message_.size());
        int n = msgsnd(msgid_, &bufferin, sizeof(bufferin.mtext), 0);
        if (n < 0)
        {
            cout << " msgsnd error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(Msgsnd_Error);
        }
    }

    string Recv_Base(int mtype_)
    {
        struct Msgbuf bufferout;
        memset(bufferout.mtext, 0, sizeof(bufferout.mtext));
        int n = msgrcv(msgid_, &bufferout, sizeof(bufferout.mtext), mtype_, 0);
        if (n < 0)
        {
            cout << " msgrcv error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(MsgRcv_Error);
        }

        // 将队列中的信息解析出来
        return bufferout.mtext;
    }

protected:
    int key_;
    int msgid_;
};

// 负责消息队列的创建和释放
class Server : public Msg_q
{
public:
    Server(const string &pathname = defaultfilename, const int &proj_id = defaultproj_od)
        : Msg_q(pathname, proj_id, CreatMsg_Mode)
    {
        chain_ = new ChainOfResponsibility();
    }
    ~Server()
    {
        // 销毁消息队列
        if (msgctl(msgid_, IPC_RMID, nullptr) < 0)
        {
            cout << " msgget error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(Msgctrl_Error);
        }
        delete chain_;
    }

    void ProcessInfo(int mtype_)
    {
        if (mtype_ < 0)
        {
            cout << " mtype_ error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(MsgRcvType_Error);
        }
        string message = Recv_Base(mtype_);
        chain_->Run(message);
    }
private:
    ChainOfResponsibility *chain_ = nullptr;
};

class Client : public Msg_q
{
public:
    Client(const string &pathname = defaultfilename, const int &proj_id = defaultproj_od)
        : Msg_q(pathname, proj_id, GetMsg_Mode)
    {
    }

    void Send(const string &message_, int mtype_)
    {
        // 进行发送消息
        if (mtype_ < 0)
        {
            cout << " mtype_ error " << "int file :" << __FILE__ << " on line : " << __LINE__ << endl;
            exit(MsgsndType_Error);
        }
        Send_Base(message_, mtype_);
    }
    ~Client()
    {
    }
};

#endif